/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package MNetSockets.CmdChanel;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.json.JSONObject;

/**
 *
 * @author wcss
 */
public class CmdClient implements Runnable {

    private Socket selfsocket = null;
    private IDataReader dataReadEvent;
    private IConnectionState connectionEvent;
    private PrintWriter gos;
    private BufferedReader gis;
    private Thread thRead;
    private String tag;
    private CmdServer parentComponent = null;
    private String conId;
    //protected static Thread thShellClient;
    //public Queue<char[]> queue = new LinkedList<char[]>();

    public void handleDataRead(Object data) {
        if (getDataReadEvent() != null) {
            this.getDataReadEvent().dataRead(this, data);
        }
    }

    public void handleConnectionState(String state, String tag) {
        if (getConnectionEvent() != null) {
            getConnectionEvent().changeState(this, state, tag);
        }
    }

    public Boolean getConnected() {
        try {
            return selfsocket.isConnected();
        } catch (Exception ex) {
            return false;
        }
    }

    public Boolean isSubClient() {
        return parentComponent != null;
    }

    public CmdClient() {
        parentComponent = null;
    }

    public CmdClient(CmdServer par, String cid,Socket sub, IDataReader reader, IConnectionState state) throws Exception {
        parentComponent = par;
        conId = cid;
        selfsocket = sub;
        this.dataReadEvent = reader;
        this.connectionEvent = state;
        gos = new PrintWriter(selfsocket.getOutputStream());
        gis = new BufferedReader(new InputStreamReader(selfsocket.getInputStream()));
        this.thRead = new Thread(this);
        this.thRead.setDaemon(true);
        this.thRead.start();
//        this.thShell = new Thread(new CmdRun(this));
//        this.thShell.setDaemon(true);
//        this.thShell.start();
        this.handleConnectionState("sub-open", "");
    }

    public void connect(String host, int port) throws Exception {
        selfsocket = new Socket();
        selfsocket.connect(new InetSocketAddress(host, port));
        gos = new PrintWriter(selfsocket.getOutputStream());
        gis = new BufferedReader(new InputStreamReader(selfsocket.getInputStream()));
        this.thRead = new Thread(this);
        this.thRead.setDaemon(true);
        this.thRead.start();
//        this.thShell = new Thread(new CmdRun(this));
//        this.thShell.setDaemon(true);
//        this.thShell.start();
        this.handleConnectionState("open", "");
    }

    public void send(String data) {
        try {
            gos.write((data + "###").toCharArray());
            gos.flush();
        } catch (Exception ex) {
            this.close();
        }
    }

    public void sendWithJson(Object obj) {
        JSONObject jsons = JSONObject.fromObject(obj);
        System.out.println("send JSon:" + jsons.toString());
        send(jsons.toString());
    }

    public void close() {
        try {
            gos.close(); //关闭Socket输出流
            gis.close(); //关闭Socket
            selfsocket.close(); //关闭Socket
        } catch (IOException ex) {
            Logger.getLogger(CmdClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    StringBuilder stringBuffer = new StringBuilder();
    String stringContent = null;

    @Override
    public void run() {
        //stringBuffer.delete(0, stringBuffer.length() - 1);
        stringContent = "";
        int flagindex = 0;
        int msgLength = 0;

        while (this.selfsocket.isConnected()) {
            String str = null;
            char[] team = new char[1024];
            try {
                if (gis != null) {
                    //System.out.println("wait...");
                    msgLength = gis.read(team);
//                    if (msgLength > 0)
//                    {
                    //this.queue.offer(team);
                    stringBuffer.append(team);
//                    }else
//                    {
//                       throw new Exception("connection closed");
//                    }
                }
            } catch (Exception ex) {
                Logger.getLogger(CmdClient.class.getName()).log(Level.SEVERE, null, ex);
                //this.handleConnectionState("close", "");
                break;
            }

            while (stringBuffer.length() > 0) {
                flagindex = stringBuffer.indexOf("###");
                if (flagindex > 0) {
                    stringContent = stringBuffer.substring(0, flagindex + 3);
                    stringBuffer.delete(0, flagindex + 3);
                    stringContent = stringContent.trim();
                    stringContent = stringContent.substring(0, stringContent.length() - 3);
                    this.handleDataRead(stringContent);
                } else {
                    stringBuffer.delete(0, stringBuffer.length() - 1);
                    break;
                }
            }

            try {
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                Logger.getLogger(CmdClient.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        try {
            this.handleConnectionState("closing", null);
            this.close();
            this.handleConnectionState("closed", null);
        } catch (Exception ex) {
            Logger.getLogger(CmdClient.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * @return the tag
     */
    public String getTag() {
        return tag;
    }

    /**
     * @param tag the tag to set
     */
    public void setTag(String tag) {
        this.tag = tag;
    }

    /**
     * @return the dataReadEvent
     */
    public IDataReader getDataReadEvent() {
        return dataReadEvent;
    }

    /**
     * @param dataReadEvent the dataReadEvent to set
     */
    public void setDataReadEvent(IDataReader dataReadEvent) {
        this.dataReadEvent = dataReadEvent;
    }

    /**
     * @return the connectionEvent
     */
    public IConnectionState getConnectionEvent() {
        return connectionEvent;
    }

    /**
     * @param connectionEvent the connectionEvent to set
     */
    public void setConnectionEvent(IConnectionState connectionEvent) {
        this.connectionEvent = connectionEvent;
    }

    /**
     * @return the conId
     */
    public String getConId() {
        return conId;
    }

    /**
     * @param conId the conId to set
     */
    public void setConId(String conId) {
        this.conId = conId;
    }
}
